package com.hu.thread;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.RandomUtil;
import com.hu.config.Config;
import com.hu.InputFrame;
import com.hu.util.FileUtils;
import com.hu.util.ReadExcelUtils;
import com.hu.util.SeleniumUtil;
import com.microsoft.playwright.*;
import com.microsoft.playwright.options.Proxy;
import org.apache.log4j.Logger;
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeDriverService;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;

import java.awt.*;
import java.awt.Dimension;
import java.awt.event.KeyEvent;
import java.io.*;
import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.time.Duration;
import java.util.*;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.zip.CRC32;
import java.util.zip.CheckedOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import static org.openqa.selenium.support.ui.ExpectedConditions.presenceOfAllElementsLocatedBy;
import static org.openqa.selenium.support.ui.ExpectedConditions.presenceOfElementLocated;


public class WorkThread extends Thread {


    public WorkThread(InputFrame frame,Integer port) {
        this.frame = frame;
        sleepFlag = false;
        this.config = frame.getConfig();
        this.port = port;
    }

    private boolean sleepFlag;

    private InputFrame frame;
    private WebDriver driver;
    private WebDriverWait wait;
    private int startScrollLen;
    private int endScrollLen;

    private Integer port;

    private String projectPath;
    private int scrollLength;
    private List<Config> configs = new ArrayList<>();
    private Config config;
    private SeleniumUtil util;
//
//    private String proxyServer = "geo.iproyal.com";
//    private Integer proxyHost = 12321;

    private String pluginPath;


    private int proxyIdx;
    private Robot robot;
    private Logger logger = Logger.getLogger(WorkThread.class);

    @Override
    public void run() {

        Toolkit toolkit = Toolkit.getDefaultToolkit();
        Dimension dimension = toolkit.getScreenSize();
        startScrollLen = 0;
        scrollLength = 400;
        proxyIdx = 0;
        endScrollLen = scrollLength;
        projectPath = System.getProperty("user.dir") + "\\..\\..";
        try {
            projectPath = new File(projectPath).getCanonicalFile().getAbsolutePath();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        pluginPath = "d:\\proxy.zip";

        ReadExcelUtils excelUtils = new ReadExcelUtils(config.getExcelPath());
        robot = null;
        try {
            String[] strings1 = excelUtils.readExcelTitle();
            List<Map> list = excelUtils.readExcelContent(Arrays.asList(strings1));
            for (Map map : list){
                if(map.get("关键词").toString().equals("") || map.get("图片地址").toString().equals("")){
                    continue;
                }
                configs.add(new Config(map.get("关键词").toString(), map.get("图片地址").toString()));
            }
            robot = new Robot();
        } catch (Exception e) {
            
            logger.error(ExceptionUtil.stacktraceToString(e));
            showLog("导入Excel出现异常");
            showLog(ExceptionUtil.stacktraceToString(e));
        }

//        testPlaywright();
//        boolean is = false;
//        if(!is){
//            return;
//        }

        System.setProperty("webdriver.chrome.driver",projectPath+"\\chromedriver.exe");



        for (int i = 0; i < config.getRunCount(); i++) {
            showLog("第"+(i+1)+"次运行");
            for (Config c: configs) {


                while (isSleepFlag()){
                    try {
                        sleep(1000);
                    } catch (InterruptedException e) {

                        logger.error(ExceptionUtil.stacktraceToString(e));
                        showLog("等待超时");
                        showLog(ExceptionUtil.stacktraceToString(e));
                    }
                }

                try {
                    clickProxy();
                    ChromeOptions options = addOptions();
                    driver = new ChromeDriver(options);
                    wait = new WebDriverWait(driver, 5);
                    util = SeleniumUtil.getInstance(driver,wait);
                    startScrollLen = 0;
                    endScrollLen = scrollLength;
                    loop(c);
                } catch (Exception e) {
                    logger.error(ExceptionUtil.stacktraceToString(e));
                    showLog("卡住了,等待");
                }
            }
        }


    }

    public void clickProxy() throws InterruptedException {
        String proxyClickPoses = frame.getProxyClickPoses();
        String[] split = proxyClickPoses.split("\\|");
        if(proxyIdx == split.length){
            proxyIdx = 0;
        }

        String s = split[proxyIdx];
        String[] arr = s.split(",");

        click(Integer.parseInt(arr[0]),Integer.parseInt(arr[1]));
        sleep(2000);
        proxyIdx++;
    }

    public void testPlaywright(){
//        String ip = "_country-jp_session-dr63YxcD_lifetime-12m_streaming-1geo.iproyal.com";
//        int port = 12321;
//        String user = "sjy1998";
//        String password = "123456";:
        String server = "socks5h://sjy1998:123456_country-jp_session-sv0drUJ8_lifetime-12m_streaming-1@geo.iproyal.com:32325";
        String pageUrl = "https://ipv4.icanhazip.com";
        try (Playwright playwright = Playwright.create()) {
            // 设置浏览器类型
            BrowserType browserType = playwright.webkit();
            BrowserType.LaunchOptions launchOptions = new BrowserType.LaunchOptions();

            Proxy proxy = new Proxy(server);
            launchOptions.setProxy(proxy);

            // 启动浏览器并应用全局代理
            Browser browser = browserType.launch(launchOptions);

            // 创建一个页面
            Page page = browser.newPage();

            // 访问网页
            page.navigate(pageUrl);
            System.out.println(page.title());

            browser.close();
        }
    }

    private ChromeOptions addOptions(){
        ChromeOptions options = new ChromeOptions();
        options.setBinary(new File(projectPath+"\\Chrome\\App\\Chrome.exe"));

        options.addArguments("incognito");//启动无痕/隐私模式
        options.addArguments("start-maximized");
        options.addArguments("--disable-gpu");//禁止gpu渲染
        options.addArguments("–-no-sandbox");//关闭沙盒模式
        options.addArguments("--disable-dev-shm-usage");
//        HashMap<String, Object> prefs = new HashMap<>();
//        prefs.put("profile.default_content_settings", 2);
//        options.setExperimentalOption("prefs", prefs);
        options.addArguments("blink-settings=imagesEnabled=false");//禁用图片

        // 创建代理对象
//        Proxy proxy = new Proxy();
//        proxy.setHttpProxy(proxyServer + ":" + proxyHost)
//                .setSslProxy(proxyServer + ":" + proxyHost);
//
//        options.setProxy(proxy);

//        frame.refresh();
//        String up = frame.getUsername().trim();
//
//        String[] split = up.split(":");
//
//        String pluginPath = createProxyAuthExtension(split[0], Integer.parseInt(split[1]), split[2], split[3]);
////        pluginPath
////        settingProxy(options,split[0],split[1],split[2],split[3]);
//
//        options.addExtensions(new File(pluginPath));
        return options;
    }


//    private void zip(String username,String password){
//        String manifestJson = "{\n" +
//                "  \"manifest_version\": 2,\n" +
//                "  \"name\": \"Authentication for ...\",\n" +
//                "  \"version\": \"1.0.0\",\n" +
//                "  \"permissions\": [\"<all_urls>\", \"webRequest\", \"webRequestBlocking\"],\n" +
//                "  \"background\": {\n" +
//                "    \"scripts\": [\"background.js\"]\n" +
//                "  }\n"+
//                "}";
//
//        String backgroundJs =
//                "function callbackFn(details) {\n" +
//                "    return {\n" +
//                "        authCredentials: {\n" +
//                "            username: \"" + username + "\",\n" +
//                "            password: \"" + password + "\"\n" +
//                "        }\n" +
//                "    };\n" +
//                "}\n" +
//                "\n" +
//                "chrome.webRequest.onAuthRequired.addListener(\n" +
//                "            callbackFn,\n" +
//                "            {urls: [\"<all_urls>\"]},\n" +
//                "            ['blocking']\n" +
//                ");";
//
//        HashMap<String,String> hashMap = new HashMap<>();
//        hashMap.put("manifest.json", manifestJson);
//        hashMap.put("background.js", backgroundJs);
//        zipFile(hashMap);
//    }

    public static String createProxyAuthExtension(String proxyHost, int proxyPort, String proxyUsername, String proxyPassword) {
        String pluginPath = "D:\\chrome_proxyauth_plugin.zip";
//        String pluginPath = "Selenium-Chrome-HTTP-Private-Proxy.zip";

        String manifestJson = "{\n" +
                "    \"version\": \"1.0.0\",\n" +
                "    \"manifest_version\": 2,\n" +
                "    \"name\": \"Chrome Proxy\",\n" +
                "    \"permissions\": [\n" +
                "        \"proxy\",\n" +
                "        \"tabs\",\n" +
                "        \"unlimitedStorage\",\n" +
                "        \"storage\",\n" +
                "        \"<all_urls>\",\n" +
                "        \"webRequest\",\n" +
                "        \"webRequestBlocking\"\n" +
                "    ],\n" +
                "    \"background\": {\n" +
                "        \"scripts\": [\"background.js\"]\n" +
                "    },\n" +
                "    \"minimum_chrome_version\":\"22.0.0\"\n" +
                "}";

        String backgroundJs = String.format(
                "var config = { \n" +
                        "  mode: \"fixed_servers\", \n" +
                        "  rules: { \n" +
                        "    singleProxy: { \n" +
                        "      scheme: \"%s\", \n" +
                        "      host: \"%s\", \n" +
                        "      port: parseInt(%d) \n" +
                        "    }, \n" +
                        "    bypassList: [\"foobar.com\"] \n" +
                        "  } \n" +
                        "}; \n" +
                        "chrome.proxy.settings.set({value: config, scope: \"regular\"}, function() {}); \n" +
                        "function callbackFn(details) { \n" +
                        "  return { \n" +
                        "    authCredentials: { \n" +
                        "      username: \"%s\", \n" +
                        "      password: \"%s\" \n" +
                        "    } \n" +
                        "  }; \n" +
                        "} \n" +
                        "chrome.webRequest.onAuthRequired.addListener( \n" +
                        "  callbackFn, \n" +
                        "  {urls: [\"<all_urls>\"]}, \n" +
                        "  ['blocking'] \n" +
                        "); \n",
                "http", proxyHost, proxyPort, proxyUsername, proxyPassword
        );

        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(pluginPath))) {
            zos.putNextEntry(new ZipEntry("manifest.json"));
            zos.write(manifestJson.getBytes());
            zos.closeEntry();

            zos.putNextEntry(new ZipEntry("background.js"));
            zos.write(backgroundJs.getBytes());
            zos.closeEntry();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return pluginPath;
    }

    public static String createProxyAuthExtensio3(String proxyHost, int proxyPort, String proxyUsername, String proxyPassword) {
        String pluginPath = "./chrome_proxyauth_plugin.zip";

        String manifestJson = "{\n" +
                "    \"version\": \"1.0.0\",\n" +
                "    \"manifest_version\": 2,\n" +
                "    \"name\": \"Chrome Proxy\",\n" +
                "    \"permissions\": [\n" +
                "        \"proxy\",\n" +
                "        \"tabs\",\n" +
                "        \"unlimitedStorage\",\n" +
                "        \"storage\",\n" +
                "        \"<all_urls>\",\n" +
                "        \"webRequest\",\n" +
                "        \"webRequestBlocking\"\n" +
                "    ],\n" +
                "    \"background\": {\n" +
                "        \"scripts\": [\"background.js\"]\n" +
                "    },\n" +
                "    \"minimum_chrome_version\":\"22.0.0\"\n" +
                "}";

        String backgroundJs = "var config = {\n" +
                "    mode: \"fixed_servers\",\n" +
                "    rules: {\n" +
                "      singleProxy: {\n" +
                "        scheme: \"" + (proxyUsername == null ? "http" : "http") + "\",\n" +
                "        host: \"" + proxyHost + "\",\n" +
                "        port: parseInt(" + proxyPort + ")\n" +
                "      },\n" +
                "      bypassList: [\"foobar.com\"]\n" +
                "    }\n" +
                "  };\n" +
                "chrome.proxy.settings.set({value: config, scope: \"regular\"}, function() {});\n" +
                "function callbackFn(details) {\n" +
                "    return {\n" +
                "        authCredentials: {\n" +
                "            username: \"" + (proxyUsername != null ? proxyUsername : "") + "\",\n" +
                "            password: \"" + (proxyPassword != null ? proxyPassword : "") + "\"\n" +
                "        }\n" +
                "    };\n" +
                "}\n" +
                "chrome.webRequest.onAuthRequired.addListener(\n" +
                "            callbackFn,\n" +
                "            {urls: [\"<all_urls>\"]},\n" +
                "            ['blocking']\n" +
                ");";

        try (ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(pluginPath))) {
            zos.putNextEntry(new ZipEntry("manifest.json"));
            zos.write(manifestJson.getBytes());
            zos.closeEntry();

            zos.putNextEntry(new ZipEntry("background.js"));
            zos.write(backgroundJs.getBytes());
            zos.closeEntry();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return pluginPath;
    }


//    private void zipFile(Map<String,String> map) {
//        try {
//            File file = new File(pluginPath);
//
//            ZipOutputStream zos = new ZipOutputStream(new FileOutputStream(file));
//            for (Map.Entry<String,String> entry : map.entrySet()) {
//                ByteArrayOutputStream bos = new ByteArrayOutputStream();
//                CheckedOutputStream cos = new CheckedOutputStream(bos, new CRC32());
//                transfer(new ByteArrayInputStream(entry.getValue().getBytes()), cos);
//                ZipEntry zipEntry = new ZipEntry(entry.getKey());
//                zipEntry.setTime(System.currentTimeMillis());
//                zipEntry.setMethod(ZipEntry.STORED);
//                zipEntry.setSize(bos.size());
//                zipEntry.setCrc(cos.getChecksum().getValue());
//                zos.putNextEntry(zipEntry);
//                ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
//                transfer(bis, zos);
//                zos.closeEntry();
//            }
//            zos.finish();
//        }catch (Exception e){
//            e.printStackTrace();
//        }
//    }

    public static long transfer(InputStream in, OutputStream out) throws IOException {
        long total = 0;
        byte[] buffer = new byte[4096];
        int length;
        while ((length = in.read(buffer)) != -1) {
            out.write(buffer, 0, length);
            total += length;
        }
        out.flush();
        return total;
    }

    private void stopBrowser(Integer port){
        driver.quit();
//        try {
//            String command = "taskkill /F /FI \"Cnnnnections eq " + port + "\" /IM chrome.exe";
//            Runtime.getRuntime().exec(command);
//            System.out.println("Chrome实例已成功关闭");
//        } catch (IOException e) {
//            System.out.println(ExceptionUtil.stacktraceToString(e));
//        }
    }

    private void startBrowser(String chromePath,Integer port){
        String cmdCommand = chromePath + " --user-data-dir="+projectPath+"\\chromeData --start-maximized --blink-settings=imagesEnabled=false --incognito --remote-debugging-port="+port;

        try {
            Runtime.getRuntime().exec(cmdCommand);
        } catch (IOException e) {
            System.out.println(ExceptionUtil.stacktraceToString(e));
        }
    }

    private void showLog(String msg) {
        System.out.println(msg);
        frame.showLog(msg);
    }

    private void loop(Config config) throws InterruptedException {
        try {
//            driver.get("https://www.ipaddress.my/?lang=zh_CN");
//            driver.get("https://ip.cn");
//            driver.get("https://www.google.com");
//            System.out.println(driver.getPageSource());
            driver.get("https://shopping.yahoo.co.jp/?sc_i=shp_pc_store_MhdLogo");
            wait.until(ExpectedConditions.presenceOfElementLocated(By.name("p")));
            sleep(1000);
            driver.findElement(By.name("p")).sendKeys(config.getTitle());
            sleep(1000);
            wait.until(presenceOfElementLocated(By.xpath("//button[@type=\"submit\"]"))).click();
            wait.until(ExpectedConditions.titleContains("商品一覧"));
            sleep(1000);
        }catch (Exception e) {
            showLog("网页异常,跳过");
            sleep(3000);
            frame.refresh();
            stopBrowser(port);
            logger.error(ExceptionUtil.stacktraceToString(e));
            return;
        }

        try {
            util.clickElementIfExist(By.xpath("//span[text()=\"確認しました\"]"));

            int i;
            for (i = 0; i < 50; i++) {
                if((i+1) % 10 ==0){
                    showLog("第"+(i+1)+"次滑动");
                }
                ((JavascriptExecutor) driver).executeScript("window.scrollTo(" + startScrollLen + "," + endScrollLen + ");");
                startScrollLen += scrollLength;
                endScrollLen += scrollLength;
                sleep(1000);
                List<WebElement> elements = wait.until(presenceOfAllElementsLocatedBy(By.xpath("//img[contains(@class,\"ItemImageLink_SearchResultItemImageLink__imageSource\")]")));

                boolean flag = false;
                for (WebElement element : elements) {
                    String src = element.getAttribute("src");
                    if (element.isDisplayed() && src.contains(config.getLink())) {
                        element.click();
                        flag = true;
                        break;
                    }
                }
                if(flag){
                    break;
                }
            }



            if(i >= 50){
                showLog("滑动50次未找到指定商品,下一个");

                stopBrowser(port);
                return;
            }

            sleep(10000);
            Set<String> handles = driver.getWindowHandles();
            Iterator<String> iterator = handles.iterator();
            while (iterator.hasNext()) {
                String h = iterator.next();
                if(!driver.getTitle().contains("商品一覧")){
                    break;
                }
                driver.switchTo().window(h);
            }
            showLog("开始加购");
            util.clickElement(By.xpath("//button[contains(@class,\"styles_cartButton\")]"));
            util.clickElement(By.xpath("//button[@data-testid=\"orderOptionCartButton\"]"));
//            util.clickElement(By.className("elCartButton"));
            sleep(2000);
            showLog("加购完成");
        }catch (Exception e){
            showLog("网页异常,跳过");
            logger.error(ExceptionUtil.stacktraceToString(e));
        }finally {
            stopBrowser(port);
        }

    }


    private void test() throws InterruptedException {
        projectPath = System.getProperty("user.dir") + "\\..\\..";
        try {
            projectPath = new File(projectPath).getCanonicalFile().getAbsolutePath();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        System.setProperty("webdriver.chrome.driver",projectPath+"\\chromedriver.exe");
        ChromeOptions options = new ChromeOptions();
        ChromeDriverService service = null;
        options.addArguments("incognito");//启动无痕/隐私模式
        options.addArguments("start-maximized");
        options.addArguments("--disable-gpu");//禁止gpu渲染
        options.addArguments("–-no-sandbox");//关闭沙盒模式
        options.addArguments("--disable-dev-shm-usage");
        HashMap<String, Object> prefs = new HashMap<>();
        prefs.put("profile.default_content_settings", 2);
        options.setExperimentalOption("prefs", prefs);
        options.addArguments("blink-settings=imagesEnabled=false");//禁用图片
        options.setExperimentalOption("debuggerAddress","localhost:"+port); // 设置端口号
        options.addArguments("--blink-settings=imagesEnabled=false");
        options.setBinary(new File(projectPath+"\\Chrome\\App\\Chrome.exe"));
        options.addArguments("user-data-dir="+projectPath+"\\chromeData");


        service = ChromeDriverService.createDefaultService();
        driver = new ChromeDriver(options);
        wait = new WebDriverWait(driver, 20);
        util = SeleniumUtil.getInstance(driver,wait);
        driver.get("https://store.shopping.yahoo.co.jp/massanshop/msgj-236a.html?sc_i=shp_pc_search_itemlist_shsrg_img");
        util.clickElement(By.id("add_cart"));
        sleep(1000);
        util.clickElement(By.className("elChoiceItem"));
        sleep(1000);
        util.clickElement(By.className("elCartButton"));


    }


    private void click(int x,int y){
        robot.mouseMove(x,y);
        robot.mousePress(KeyEvent.BUTTON1_MASK);
        robot.mouseRelease(KeyEvent.BUTTON1_MASK);
    }

    public boolean isSleepFlag() {
        return frame.isStop();
    }

    public void setSleepFlag(boolean sleepFlag) {
        this.sleepFlag = sleepFlag;
    }

    private void settingProxy(ChromeOptions options,String host,String port,String user,String password){

//        System.out.println(host+":"+port);
//
//        Map<String, Object> map = new HashMap<String, Object>();
//        map.put("httpProxy", host+":"+port);
//        Proxy proxy = new Proxy(map);
//
//        options.addArguments("--proxy-server=http://127.0.0.1:7891");
//        options.setProxy(proxy);
//        zip(user,password);
//
//        System.setProperty("java.net.useSystemProxies", "true");
//
//        // http
//        System.setProperty("http.proxyHost", host);
//        System.setProperty("http.proxyPort", port);
//        System.setProperty("http.proxyUser", user);
//        System.setProperty("http.proxyPassword", password);
//
//        // https
//        System.setProperty("https.proxyHost",host);
//        System.setProperty("https.proxyPort", port);
//        System.setProperty("https.proxyUser", user);
//        System.setProperty("https.proxyPassword", password);
//
//        System.setProperty("jdk.http.auth.tunneling.disabledSchemes", "");
//        System.setProperty("jdk.https.auth.tunneling.disabledSchemes", "");
//
//        Authenticator.setDefault(new Authenticator() {
//            @Override
//            public PasswordAuthentication getPasswordAuthentication() {
//                return new PasswordAuthentication(user, password.toCharArray());
//            }
//        });
    }
}
